<!doctype html>
<html lang="en">
  <head>
<!--    <link rel="stylesheet" href="http://10.70.94.96:8080/geoserver/openlayers3/ol.css" type="text/css"> -->
    <link rel="stylesheet" href="https://openlayers.org/en/v4.4.2/css/ol.css" type="text/css">
   <link rel="stylesheet" href="../../statics/css/jquery-ui.min.css">
   		<script src="../../statics/js/jquery-3.2.1.min.js"></script>
		<script src="../../statics/js/jquery-ui.min.js"></script>
    <style>
      .map {
            width: 768px;
            height: 400px;
            float:left;
            border: 1px solid black;
      }
      .ol-popup {
        position: absolute;
        background-color: white;
        -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
        filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
        padding: 15px;
        border-radius: 10px;
        border: 1px solid #cccccc;
        bottom: 12px;
        left: -50px;
        min-width: 280px;
      }
      .ol-popup:after, .ol-popup:before {
        top: 100%;
        border: solid transparent;
        content: " ";
        height: 0;
        width: 0;
        position: absolute;
        pointer-events: none;
      }
      .ol-popup:after {
        border-top-color: white;
        border-width: 10px;
        left: 48px;
        margin-left: -10px;
      }
      .ol-popup:before {
        border-top-color: #cccccc;
        border-width: 11px;
        left: 48px;
        margin-left: -11px;
      }
      .ol-popup-closer {
        text-decoration: none;
        position: absolute;
        top: 2px;
        right: 8px;
      }
      .ol-popup-closer:after {
        content: "✖";
      }
    </style>
<!--    <script src="http://10.70.94.96:8080/geoserver/openlayers3/ol.js" type="text/javascript"></script> -->
      <script src="https://openlayers.org/en/v4.4.2/build/ol.js" type="text/javascript"></script>
    <title>TestOpenLayer</title>
  </head>
  <body>

    <div id="map" class="map">
    	<div id="location" style="width:10px; height:10px; z-index: 1;position: absolute;"></div>
    </div>  
    <div style="float:left; width:100px; height:200px">
    	<div>
		    <form class="form-inline">
		      <label>Geometry type &nbsp;</label>
		      <select id="type">
		      	<option value="None">None</option>
		        <option value="Point">Point</option>
		        <option value="LineString">LineString</option>
		        <option value="Polygon">Polygon</option>
		        <option value="Circle">Circle</option>  
		      </select>
		    </form>
    	</div>
		<button id="undo">undo</button>
		<button id="update">update</button>
		<button id="delete">delete</button>
		<button id="add">add</button>
    </div>
    
    <script type="text/javascript">
	    var container = document.getElementById('popup');
	    var content = document.getElementById('popup-content');

	    
   		var format = 'image/png';
   		var raster = new ol.layer.Tile({
   	        source: new ol.source.OSM()
   	    });
 		var source =  new ol.source.Vector({wrapX: false});
   		var vctlayer = new ol.layer.Vector({
   	        source: source
   	    });

		var mousePositionControl = new ol.control.MousePosition({
		    className: 'custom-mouse-position',
		    target: document.getElementById('location'),
		    coordinateFormat: ol.coordinate.createStringXY(5),
		    undefinedHTML: '&nbsp;'
		});	
	    var projection = new ol.proj.Projection({
			code: 'EPSG:4326',
			units: 'degrees',
			axisOrientation: 'neu',
			global: true
	      });
        var map = new ol.Map({
        	controls: ol.control.defaults({
  		      attribution: false
  		    }).extend([mousePositionControl]),
            layers: [raster, vctlayer],
            target: 'map',
		    view: new ol.View({
			       projection: projection
			})
        });
        var bounds = [110, 35,
                      115, 40];  //这个设置不当会报错，具体规则不知道！！！
    	map.getView().fit(bounds, map.getSize());
 
		var pointId = 0;
		var lineId = 0;
		var typeSelect = document.getElementById('type');
		var StationStyle = new ol.style.Style({
			image : new ol.style.Icon(({
				size : [ 48, 48 ],
				anchor : [ 0.35, 0.5 ],
				src : '../../statics/img/Station.gif',
				scale: 1
			}))
		});
		var collection = new ol.Collection(
			new Array(),
			{unique: true}
		);
		var draw, snap; // global so we can remove it later
		var needRedraw, needClean;
		/** modify有问题，暂时关闭*/
// 		var modify = new ol.interaction.Modify({source: source});
// 		map.addInteraction(modify);
		 

	    function addInteraction() {
	        var value = typeSelect.value;
	        draw = undefined;
	        if (value !== 'None') {
	          	
	          draw = new ol.interaction.Draw({
	        	features: collection,
	            source: source,
	            type: value,
// 	            geometryName: "point",
// 	          	style: StationStyle
	          });     
	          map.addInteraction(draw);
  	          snap = new ol.interaction.Snap({source: source});
	          map.addInteraction(snap);  //这个必须每次都添加，否则点线将会分离无法一起拖动，原因不明！
	        } 
	        
	        if(draw != undefined) {
	        	draw.on('drawend', function(e){
	        		var feature = e.feature;
	        		var geom = feature.getGeometry();
	        		var idStr = "";
	        		console.log("drawend，" + geom.getCoordinates());
	        		needRedraw = isNeedRedraw(feature, value);
	        		if (needRedraw != null && needRedraw != undefined) {
	        			needClean = feature;
	        			console.log("重复绘制，需要清理");
	        			return;
	        		}
	        			
	        		if (value == 'Point') {
	        			idStr  = value + pointId++;
	        			feature.setStyle(StationStyle);
	        			geom.setProperties({"lines": new Array()}, true);
	        		} else if (value == 'LineString') {
	        			idStr  = value + lineId++;
	        			geom.setProperties({"points": new Array()}, true);
	        			addLineToPoint(feature);
	        			addPointToLine(feature);
	        		}
	        		//geom.setProperties({"id": idStr}, true); //绘图模式下，重复点击一个点会刷新这个id，待解决(先判断是否是已经存在)
	        		feature.setId(idStr);
	        	});
	        	
	        	draw.on('drawstart', function(e){
	        		redrawFeature();
	        	});
	    	}
		}
	    addInteraction();
	    
	    function redrawFeature() {
	    	if (needRedraw == undefined || needClean == undefined || needRedraw == null || needClean == null)
	    		return;	
	    	console.log("redraw");
	    	collection.remove(needClean);
	    	vctlayer.getSource().removeFeature(needClean);
	    	vctlayer.getSource().addFeature(needRedraw);
	    	needClean = null;
	    	needRedraw = null;
	    }
	    
	    function isNeedRedraw(newFeature, type) {
	    	var redrawFeature = null;
	    	collection.forEach(function(feature, index, array){
	    		if (getFeatureType(newFeature) == getFeatureType(feature)) {
	    			if (arrayEqual(newFeature.getGeometry().getCoordinates(), feature.getGeometry().getCoordinates())) {
	    				redrawFeature = feature;
	    				return;
	    			}
	    		}
	    	}, this);
			return redrawFeature;
	    }
	    
	    function arrayEqual(array1, array2) {
	    	if(array1 == null || array1 == undefined ||array2 == null || array2 == undefined)
	    		return false;
	    	if(array1.length != array2.length)
	    		return false;
	    	for (i in array1) {
	    		if (array1[i] instanceof Array && array2[i] instanceof Array) {
	    			if (!arrayEqual(array1[i], array2[i]))
	    				return false;
	    		} else if (array1[i] != array2[i]){
	    			return false;
	    		}
	    	}
	    	return true;
	    }
	    
		  //撤销， 只对线条生效
	    $('#undo').bind('click', function(){
			console.log("undo!"); 
			draw.removeLastPoint();
		});
		
		//将线元素加入到所有穿过的点维护的线列表中。
		function addLineToPoint(line) {
			if (!(line.getGeometry() instanceof ol.geom.LineString)) {
				return;
			}
			var lineCoos = line.getGeometry().getCoordinates();
			collection.forEach(function(feature, index, array){
				var geom = feature.getGeometry();
				if (geom instanceof ol.geom.Point) {
					var pCoo = geom.getCoordinates();
					var pLines = geom.getProperties().lines; //点元素维护的线元素列表		
					var lPoints = line.getGeometry().getProperties().points; //线元素维护的点元素列表
					for (i in lineCoos) {
						if (pCoo[0] == lineCoos[i][0] && pCoo[1] == lineCoos[i][1]) {
							pLines.push(line);	//将line加入到点元素维护的线元素列表
							lPoints.push(feature); //将点加入到line维护的点元素列表
							break;
						}
					}
				}
			}, this);
		}
		//将位于线上的点元素加入到线维护的点元素列表中
		function addPointToLine(line) {
			if (!(line.getGeometry() instanceof ol.geom.Point)) {
				return;
			}
			var lineCoos = line.getGeometry().getCoordinates();
			collection.forEach(function(feature, index, array){
				var geom = feature.getGeometry();
				if (geom instanceof ol.geom.Point) {
					var pCoo = geom.getCoordinates();
					var pLines = geom.getProperties().lines; //获得点元素维护的线元素列表			
					for (i in lineCoos) {
						if (pCoo[0] == lineCoos[i][0] && pCoo[1] == lineCoos[i][1]) {
							pLines.push(line);	//将自身加入到点元素维护的线元素列表
							break;
						}
					}
				}
			}, this);
		}
	     
		typeSelect.onchange = function() {
			redrawFeature();
			map.removeInteraction(draw);
	        map.removeInteraction(snap);
// 	        if (typeSelect.value != 'None') {
// 	        	map.addInteraction(modify);
// 	        } else {
//				//移除，防止点击一个point的时候出现两个feature(多出来的一个很迷，不知道哪来的)
// 	        	map.removeInteraction(modify); 
// 	        	//剩余问题：remove后还是能拖动矢量元素！
//				//剩余问题：remove后点击线会在上面添加一个坐标点
// 	        }
	        addInteraction();
		};  

		var slectedFeature = undefined;
		var select= new ol.interaction.Select();
		map.addInteraction(select);//map加载该控件，默认是激活可用的
		select.on('select', function(e) { //ol.interaction.Select.Event	    	 
// 	      	var features = e.target.getFeatures();	//{Array.<ol.Feature>}
// 	        var selected = e.selected;  //{Array.<ol.Feature>}
	        var features = select.getFeatures(); //{Array.<ol.Feature>}
	        var f = features.item(features.getLength() - 1);
	        if (f.getId() != undefined) {
	       		slectedFeature = f;
	       		var geom = f.getGeometry();
	       		var coo = geom.getCoordinates();
	       		showFeature(slectedFeature);
				if (geom instanceof ol.geom.Point) {
					$("#update").removeAttr("disabled");
				} else {	
					$('#update').attr("disabled", "disabled");
				}
				addTips(f);
        	}
     	});
		
		function addTips(feature){
			var overlay = feature.getProperties().overlay;
			if (overlay == undefined || overlay == null) {
				var Tips = document.createElement('div');
				Tips.setAttribute("id", "Tips" + feature.getId());
				Tips.className = 'ol-popup';
	            
	    		var closer = document.createElement('a');
	    		closer.setAttribute("id", "TipsCloser" + feature.getId());
	    		closer.className = 'ol-popup-closer';
	    		Tips.appendChild(closer);
	    		
	    		var content = document.createElement('div');
	    		content.setAttribute("id", "TipsContent" + feature.getId());
				content.innerHTML = '</p>' + feature.getId() +'</P>';
	    		Tips.appendChild(content);
	    		
	    		overlay = new ol.Overlay({
	    			element: Tips,
	    	        autoPan: true,
	    	        autoPanAnimation: {
	    	        	duration: 250
	    	        }
		   		});	
	    		
	            closer.onclick = function() {
	            	map.removeOverlay(overlay);
//	                 overlay.setPosition(undefined);
//	                 closer.blur();
	                return false;
	            };
	    		feature.setProperties({"overlay": overlay}, true);
			} else {
				var Tips = overlay.getElement();
				var content = Tips.lastChild;
				content.innerHTML = '</p>' + feature.getId() +'</P>'; //支持元素内容更新		
//     			overlay.setElement(Tips);
    			map.removeOverlay(overlay);
			}
			overlay.setPosition(feature.getGeometry().getCoordinates());
			map.addOverlay(overlay); //手动关闭后再次添加  
		}
	      
	    $('#update').bind('click', function(){
			console.log("update!"); 
			var newCoo = [110, 30];	//临时
			var geom = slectedFeature.getGeometry();
			if (!(geom instanceof ol.geom.Point)) {
				return ;
			}
			var coo = geom.getCoordinates();
			var lines = geom.getProperties().lines;
			for (index in lines) {
				var lineGeom = lines[index].getGeometry();
				var lineCoos = lineGeom.getCoordinates();
				for (i in lineCoos) {
					if (coo[0] == lineCoos[i][0] && coo[1] == lineCoos[i][1]) {
						lineCoos[i] = newCoo;
					}
				}
				lineGeom.setCoordinates(lineCoos);
			}
			geom.setCoordinates(newCoo);		
		});
	    
	    function showCollection() {
	    	console.log("============ showCollection =============");
	    	collection.forEach(function(feature, index, array){
	    		showFeature(feature);
	    	}, this)
	    	console.log("========================================");
	    }
	    
	    function showFeature(feature) {
	    	var type = getFeatureType(feature);
	    	var delays;
	    	var log = "delays:";
	    	if ("Point" == type) {
	    		delays = getLinesByPoint(feature);
	    	} else {
	    		delays = getPointsByLine(feature);
	    	}
	    	if (delays != undefined && delays != null)
		    	for(i in delays) {
		    		log += delays[i].getId() + ",";
		    	}
	    	else 
	    		delays += "null";
	    	console.log(feature.getId() + " " + feature.getGeometry().getCoordinates());
	    	//console.log(feature.getGeometry().getCoordinates());
	    	console.log(log);
	    }
	    
	    function getPointsByLine(line) {
	    	return line.getGeometry().getProperties().points;
	    }
	    function getLinesByPoint(point) {
	    	return point.getGeometry().getProperties().lines;
	    } 
	    //使用featureId查询，返回索引
	    function getIdxOnCollect(collect, feature) {
	    	var index = -1;
	    	collect.forEach(function(f, idx, array){
	    		if (f.getId() == feature.getId()) {
	    			index = idx;
	    		}
	    	});
	    	return index;
	    }
	    //使用featureId查询，返回索引
	    function getIdxOnArray(array, feature) {
	    	var index = -1;
	    	if (array == undefined) 
	    		return index;
	    	for (i in array) {
	    		if (array[i] == undefined || array[i] == null)
	    			continue;
	    		if (array[i].getId() == feature.getId()) {
	    			index = i;
	    		}
	    	}
	    	return index; 
	    }
	    //移除点，同时移除所有以此为端点的线
	    //并将自身从穿过的线中维护的点列表中移除
	    function removePoint(point) {
	    	var lines = getLinesByPoint(point);
	    	var index = getIdxOnCollect(collection, point);
	    	collection.removeAt(index); //从collection中移除point
	    	for (i in lines) {
	    		var tmpLine = lines[i];
	    		var lineCoos = lines[i].getGeometry().getCoordinates();
	    		if(lineCoos.length < 3) { //若线只有两个点，则删除一个端点要伴随删除线
	    			removeLine(lines[i], point);
	    		} else {
	    			pCoo = point.getGeometry().getCoordinates();
	    			var cooIdx = -1;
	    	    	for (j in lineCoos) {
	    	    		if (lineCoos[j][0] == pCoo[0] && lineCoos[j][1] == pCoo[1]) {
	    	    			cooIdx = j;
	    	    			//break;
	    	    			lineCoos.splice(j, 1); //移除坐标,一条线可能多次穿过同一个点，需遍历线的全部坐标
	    	    		}
	    	    	}
	    	    	var lPoints = getPointsByLine(lines[i]);
	    	    	var pIdx = getIdxOnArray(lPoints, point);
	    	    	lPoints.splice(pIdx, 1); //从列表移除点	    	    	
	    	    	tmpLine.getGeometry().setCoordinates(lineCoos);
	    		}
	    	}
	    	source.removeFeature(point);
	    }
	    //移除线，并将自身从所有穿过的点维护的线列表中删除。
	    //参数：point(不需要处理的点， 删除点并联动删除线时加入此参数)
	    function removeLine(line, point) {
	    	var points = getPointsByLine(line);
	    	for (i in points) {
	    		if (points[i] == point) //跳过此点 
	    			continue;
	    		var plines = getLinesByPoint(points[i]);
	    		var idx = getIdxOnArray(plines, line);
	    		plines.splice(idx, 1);
	    	}
	    	var index = getIdxOnCollect(collection, line);
	    	collection.removeAt(index); //从collection中移除line
	    	source.removeFeature(line);
	    }
	    function getFeatureType(f) {
	    	geom = f.getGeometry();
	    	if (geom instanceof ol.geom.Point) {
	    		return "Point";
	    	} else if (geom instanceof ol.geom.LineString) {
	    		return "LineString";
	    	}
	    	return "unkown";
	    }
	    
	    $('#delete').bind('click', function(){
	    	var log = "collection:";
	    	collection.forEach(function(f, idx, array){
	    		log += f.getId() + ",";
	    	});
	    	console.log(log);
	    	if ("Point" == getFeatureType(slectedFeature)) {
	    		removePoint(slectedFeature);
	    	} else if ("LineString" == getFeatureType(slectedFeature)) {
	    		removeLine(slectedFeature);
	    	} 
	    	log = "collection:";
	    	collection.forEach(function(f, idx, array){
	    		log += f.getId() + ",";
	    	});
	    	console.log(log);	
	    });
	    
	    $('#add').bind('click', function(){
// 	    	var geom = new ol.geom.Point([105,35]);
// 	    	geom.setProperties({"lines": new Array()}, true);
// 	    	var feature = new ol.Feature(geom);
// 	    	feature.setStyle(StationStyle);
// 	    	vctlayer.getSource().addFeature(feature);
// 	    	collection.push(feature);
	    	showCollection();
	    });
	    
		$('#update').attr("disabled", "disabled");	
    </script>
  </body>
</html>